package actions.customer;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.TemporalType;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.faces.FacesMessages;

import utils.BacktrackingRepartoMesas;

import domain.Foto;
import domain.Mesa;
import domain.Reserva;
import domain.Reservamesa;
import domain.Restaurante;
import domain.Usuario;


@Name("booking")
@Scope(ScopeType.CONVERSATION)
@SuppressWarnings("all")
public class BookingAction implements Serializable {

	
	@In
	Usuario usuarioAutenticado;

	@In
	EntityManager em;
	
	@In
	FacesMessages facesMessages;

	@Out
	private Restaurante restauranteReserva;
	
	@Out
	private Reserva reserva = new Reserva();
	
	@DataModel
	private Set<Foto> fotosRestauranteReserva;
	
	private String fotoSeleccionada;

	private Integer numFumadores;
	private Integer numNoFumadores;

	private List<Mesa> mesasLibresFumadores;
	private List<Mesa> mesasLibresNoFumadores;
	
	
	@Begin
	//Carga la info del restaurante
	public String seleccionaRestaurante(Restaurante res){
		restauranteReserva = (Restaurante) em.createQuery("FROM Restaurante r join fetch r.fotos " +
				"WHERE r.restaurante =?").setParameter(1, res.getRestaurante()).getSingleResult();
		fotosRestauranteReserva = restauranteReserva.getFotos();
		
		//Foto por defecto
		if(fotosRestauranteReserva != null && fotosRestauranteReserva.size() > 0)
			this.fotoSeleccionada = fotosRestauranteReserva.iterator().next().getRuta();
		
		return "detallesRestaurante";
	}


	
	public void seleccionarFoto(String seleccion) {
		this.setFotoSeleccionada(seleccion);
	}
	
	
	
	public String comprobarDisponibilidad(){
		mesasLibresFumadores = new ArrayList<Mesa>();
		mesasLibresNoFumadores = new ArrayList<Mesa>();
		
		this.obtenerMesasLibres();
		
		Integer totalMesasFumadores = 0;
		Integer totalMesasNoFumadores = 0;
		
		for (Mesa mesa : mesasLibresFumadores) {
			totalMesasFumadores += mesa.getCapacidad();
		}
		
		for (Mesa mesa : mesasLibresNoFumadores) {
			totalMesasNoFumadores += mesa.getCapacidad();
		}
		
		if(this.numFumadores > totalMesasFumadores || this.numNoFumadores > totalMesasNoFumadores){
			facesMessages.add("No existen suficientes mesas disponibles para la reserva que ha solicitado.");
			return null;
		}
		
		return "hayDisponibles";
		
	}
	
	
	
	private void obtenerMesasLibres() {
		mesasLibresFumadores = em.createQuery("SELECT m FROM Mesa m WHERE m.mesa.permiteFumar = 0 AND m.mesa NOT IN (SELECT rm.mesa FROM ReservaMesa rm " +
				" WHERE rm.mesa.restaurante = " + restauranteReserva.getRestaurante() +
				" AND rm.reserva.fecha =? AND rm.reserva.almuerzo =  " + (reserva.isAlmuerzo()?0:1) + ") ORDER BY m.capacidad").
				setParameter(1, reserva.getFecha(),TemporalType.DATE).getResultList();
		
		mesasLibresNoFumadores = em.createQuery("SELECT m FROM Mesa m WHERE m.mesa.permiteFumar = 1 AND m.mesa NOT IN (SELECT rm.mesa FROM ReservaMesa rm " +
				" WHERE rm.mesa.restaurante = " + restauranteReserva.getRestaurante() +
				" AND rm.reserva.fecha =? AND rm.reserva.almuerzo =  " + (reserva.isAlmuerzo()?0:1) + ") ORDER BY m.capacidad").
				setParameter(1, reserva.getFecha(),TemporalType.DATE).getResultList();
		
	}
	
	
	
	public String confirmarReserva(){
		List<Mesa> mesasReservaFumadores;
		List<Mesa> mesasReservaNoFumadores;
		List<Reservamesa> reservamesas = new ArrayList<Reservamesa>();
		
		if(comprobarDisponibilidad() == null)
			return null;
		
		mesasReservaNoFumadores = BacktrackingRepartoMesas.distribuirMesas(mesasLibresFumadores, numFumadores.intValue());
		mesasReservaFumadores = BacktrackingRepartoMesas.distribuirMesas(mesasLibresNoFumadores, numNoFumadores.intValue());
		
		for (Mesa m : mesasReservaFumadores) {
			reservamesas.add(new Reservamesa(reserva, m));		
		}
		for (Mesa m : mesasReservaNoFumadores) {
			reservamesas.add(new Reservamesa(reserva, m));		
		}
		
		em.persist(reserva);
		
		for (Reservamesa reservamesa : reservamesas) {
			em.persist(reservamesa);
		}
		
		return "reservaRealizada";
	}



	/**********Getters & Setters**************/	
	public Restaurante getRestauranteReserva() {
		return restauranteReserva;
	}


	public void setRestauranteReserva(Restaurante restauranteReserva) {
		this.restauranteReserva = restauranteReserva;
	}



	public String getFotoSeleccionada() {
		return fotoSeleccionada;
	}



	public void setFotoSeleccionada(String fotoSeleccionada) {
		this.fotoSeleccionada = fotoSeleccionada;
	}



	public Integer getNumFumadores() {
		return numFumadores;
	}



	public void setNumFumadores(Integer numFumadores) {
		this.numFumadores = numFumadores;
	}



	public Integer getNumNoFumadores() {
		return numNoFumadores;
	}



	public void setNumNoFumadores(Integer numNoFumadores) {
		this.numNoFumadores = numNoFumadores;
	}
	
	
}